package com.lyw.i11BlockingQueue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * 1、阻塞队列：
 *    - 首先有一个共享队列，有一部分线程往队列中放数据，另一部分从里面取数据， 假如队列满了就放的那些线程
 *    就阻塞，如果队列空了取的那些线程也阻塞
 *
 * 2、阻塞队列就是支持两个附加操作的队列。两个附加的操作就是阻塞的插入和移除方法。
 *    1.支持阻塞插入的方法就是：当队列满的时候，队列会阻塞插入元素的线程，直到队列不满。
 *    2.支持阻塞移除的方法：就是在队列为空时，获取元素的线程会等待队列变为非空。
 *
 *    在阻塞队列不可用的时候，这两个附加操作提供了四种处理方式：
 *    1.抛出异常：当队列满的时候，如果再往里插入元素，会抛出illegalstateexceptuon异常，当队列为空时获取元
 *    素，抛出nosuchelementexception异常。
 *    2.返回特殊值：往队列里插入元素，插入成功返回true，否则返回false。如果是移除方法，则是从队列里取出一个
 *    元素，没有则返回null。
 *    3.一直阻塞：当队列满的时候，如果生产者线程往队列里插入元素，队列会一直阻塞生产者线程，队列为空时，也是
 *    一样的道理。
 *    4.超时退出：相当于给一直阻塞加了个时间，到这个时间如果还没操作成功，就直接退出。
 *
 * 3、Java里的阻塞队列
 *    1.ArrayBlockingQueue(常用)：由一个数组实现的有界阻塞队列，按照先进先出原则，对元素进行排序，默认不保证线
 *    程公平访问队列（这个公平概念和公平锁的公平概念类似）。
 *    2.LinkedBlockingQueue：一个链表实现的有界阻塞队列，也是先进先出原则对元素进行排序。
 *    3.PriorityBlockingQueue：一个支持优先级的无界阻塞队列，通过comparator方法或者构造参数comparator
 *    来对元素进行排序。但是不能保证同优先级元素的顺序。
 *    4.DelayQueue：支持延时获取元素的无界阻塞队列。队列使用PriorityQueue来实现。队列的元素必须实现
 *    Delayed接口。（这个队列使用场景很广泛如缓存系统设计，定时调度任务等等，这里不进行展开详细介绍，后续
 *    遇到，再进行详细介绍）
 *    5.SynchronousQueue：是一个不存储元素的阻塞队列，每一个put操作，必须等待一个take操作，否则不能继
 *    续添加元素。支持公平访问队列，默认采用非公平策略。（这个后续介绍线程池的时候，大家还会再看到它）
 *    6.LinkedTransferQueue：一个由链表组成的无界阻塞队列TransferQueue队列
 *    这个队列有两个特色的方法
 *    （1）transfer方法：如果当前有消费者在等待消费元素，transfer方法可以把生产者传入的元素立即传输给消
 *        费者。
 *    （2）tryTransfer方法：用来试探生产者传入的元素是否能直接传给消费者。如果没有消费者返回false。
 *    7.LinkedBlockingDeque：由链表组成的双向阻塞队列，会被运用在工作窃取模式中（后续我们讲解Fork/Join
 *    框架的时候，大家就可以看到了）。
 *
 * 4、阻塞队列的实现原理
 *    使用通知模式实现。所谓通知模式，就是当生产者往满的队列添加元素的时会阻塞住生产者，当消费者消费了一个队
 *    列之中的元素后，会通知生产者当前对列可用。这里我们就不展开详细介绍了，有兴趣的可以去阅读jdk源码，看下
 *    ArrayBlockingQueue的实现，它就是采用的这种模式，通过一个Contion属性实现的（和之前我们文章讲的线程
 *    之间的通信方式很像）
 * @author lyw
 * @Date 2023/7/11-上午11:25
 */
public class BlockingQueueDemo {

  public static void main(String[] args) throws InterruptedException {

    // 创建阻塞队列
    BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(2);

    // 第一组 以异常的形式通知已满
    /*// 如果满了会抛出一场
    blockingQueue.add("1");
    blockingQueue.add("2");
    blockingQueue.add("3");
    // 如果空了也会抛出异常
    blockingQueue.remove();
    blockingQueue.remove();
    blockingQueue.remove();
    // 查看首元素
    blockingQueue.element();*/

    // 第二组 以返回特殊值的形式通知队列已满
    // 放入成功返回 true，失败返回 false
    /*blockingQueue.offer("1");
    blockingQueue.offer("2");
    System.out.println(blockingQueue.offer("3"));
    // 获取成功返回值，失败返回 null
    String poll = blockingQueue.poll();
    String poll1 = blockingQueue.poll();
    System.out.println(blockingQueue.poll());
    // 查看首元素
    System.out.println(blockingQueue.peek());*/

    // 第三组 以阻塞的形式提示已满
    /*blockingQueue.put("1");
    blockingQueue.put("2");
    // 会阻塞
    blockingQueue.put("3");
    System.out.println(blockingQueue.take());
    System.out.println(blockingQueue.take());
    // 会阻塞
    System.out.println(blockingQueue.take());*/

    // 第四组 设置超时解决阻塞问题
    blockingQueue.offer("1");
    System.out.println(blockingQueue.offer("2"));
    // 时间内还放不进去就会自动结束, 返回 false
    System.out.println(blockingQueue.offer("3", 1, TimeUnit.SECONDS));
    blockingQueue.poll();
    blockingQueue.poll();
    System.out.println(blockingQueue.poll(1, TimeUnit.SECONDS));
  }
}
